package com.hitqz.robot.netty;

import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.hitqz.robot.api.dispatch.model.MessageDto;
import com.hitqz.robot.api.dispatch.protocol.ProtocolEnum;
import com.hitqz.robot.api.dispatch.protocol.dto.RobotRegisterDto;
import com.hitqz.robot.common.core.util.R;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.locks.Lock;

/**
 * @author xupeikun
 */
@Slf4j
@Component
@ChannelHandler.Sharable
public class NettyMessageHandler extends ChannelInboundHandlerAdapter {

    /**
     * 连接上服务器
     * */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ChannelCache.add(ctx);
        MessageDto messageDto= new MessageDto();
        messageDto.setSn(1);
        log.info("连接上服务器");
        messageDto.setCmd(ProtocolEnum.ROBOT_REGISTER.getCmd());
        RobotRegisterDto dto = new RobotRegisterDto();
        dto.setClientId(NettyClient.clientId);
        messageDto.setData(JSONObject.toJSONString(dto).getBytes(StandardCharsets.UTF_8));
        ChannelCache.send2All(messageDto);
    }

    /**
     * 服务器发送消息过来
     * */
    /**
     * 处理来自服务器的消息
     *
     * @param ctx 上下文
     * @param msg 接收到的消息
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        MessageDto messageDto = (MessageDto) msg;
        String data = new String(messageDto.getData(), StandardCharsets.UTF_8);
        //log.info("收到服务端信息: {}", data);
        try {
            ProtocolEnum protocolEnum = ProtocolEnum.CMD_PROTOCOL_MAP.get(messageDto.getCmd());
            if (protocolEnum.getClazz() == null) {
                // 发布通用事件
                SpringUtil.getApplicationContext().publishEvent(messageDto);
            } else {
                Object event = null;
                try {
                    event = JSONObject.parseObject(data, protocolEnum.getClazz());
                } catch (JSONException je) {
                    log.error("JSON 解析错误: {}", je.getMessage(), je);
                }
                if (event instanceof R<?>) {
                    // 发布通用事件
                    SpringUtil.getApplicationContext().publishEvent(messageDto);
                    processResultEvent(messageDto);
                } else {
                    // 发布主动推送的消息
                    SpringUtil.getApplicationContext().publishEvent(event);
                }
            }
        } catch (Exception e) {
            log.error("[netty handler] 消息解析失败: {}", e.getMessage(), e);
        }
    }

    private void processResultEvent(MessageDto messageDto) {
        Lock lock = null;
        // 后续有需要增加

        if (lock != null) {
            synchronized (lock) {
                try {
                    lock.notifyAll();
                } catch (Exception e) {
                    log.error("通知线程时发生异常: {}", e.getMessage(), e);
                }
            }
        }
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close().sync();
        super.exceptionCaught(ctx, cause);
    }



    /**
     * 服务器连接异常
     * */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        ChannelCache.remove(ctx);
        ctx.close();
        NettyClient.getInstance().connect( NettyClient.clientId,NettyClient.host, NettyClient.port);
    }



    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent idleEvent = (IdleStateEvent) evt;
            if (idleEvent.state() == IdleState.READER_IDLE) {
                // 读超时
                log.info("{} read time out", ctx.channel().remoteAddress());
            } else if (idleEvent.state() == IdleState.WRITER_IDLE) {
                // 写超时
                log.info("{} write time out", ctx.channel().remoteAddress());
                ctx.close().sync();
                ChannelCache.remove(ctx);
                super.userEventTriggered(ctx, evt);
            } else if (idleEvent.state() == IdleState.ALL_IDLE) {
                //全部
                log.info("{} all time out", ctx.channel().remoteAddress());
                ctx.close().sync();
                ChannelCache.remove(ctx);
                super.userEventTriggered(ctx, evt);
            }
        } else {
            log.info("断开与服务器的连接");
        }
        NettyClient.getInstance().connect( NettyClient.clientId,NettyClient.host, NettyClient.port);
    }


}
